﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.UI.WebControls;
using ApplicationGenerator.CommonModule;
using ApplicationGenerator.CommonWeb;
using ApplicationGenerator.DataAccess;
using ApplicationGenerator.Lists.BusinessLogic;

namespace ApplicationGenerator.Lists.Web
{
    /// <summary>
    /// Webowa kontrolka listy
    /// </summary>
    public class ListWebControl : BaseControl
    {
        #region Fields
        /// <summary>
        /// GridView, na którym będą wyświetlane kolumny listy
        /// </summary>
        private GridView _gridView;

        /// <summary>
        /// Guid wyświetlanej listy
        /// </summary>
        private Guid _listGuid;

        /// <summary>
        /// Konfiguracja listy
        /// </summary>
        private ListConfiguration _listConfiguration;

        /// <summary>
        /// Webowa kontrolka filtru
        /// </summary>
        private ListFilterControl _filterControl;

        /// <summary>
        /// Tabela, w której będą znajdować się wyniki zapytania
        /// </summary>
        private DataTable _tableWithData;

        /// <summary>
        /// Czy ma być możliwość wybrania elementu z listy
        /// </summary>
        private bool _hasListCheckboxes;

        /// <summary>
        /// Czy można wybrać wiele elementów z listy
        /// </summary>
        private bool _isMultiselect;
        #endregion

        #region Properties
        /// <summary>
        /// Id elementu nadrzędnego
        /// </summary>
        public int? ParentId
        {
            set;
            private get;
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Konstruktor tworzący listę z możliwością wyboru tylko i wyłącznie jednego elementu
        /// </summary>
        /// <param name="listGuid">Guid listy</param>
        /// <param name="isSelectJSFunction">Czy można wybierać element z listy</param>
        public ListWebControl(Guid listGuid, bool isSelectJSFunction)
            : this(listGuid, isSelectJSFunction, false)
        {
        }

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="listGuid">Guid listy</param>
        /// <param name="isSelectJSFunction">Czy można wybierać element z listy</param>
        /// <param name="isMultiselect">Czy można wybierać wiele elementów z listy</param>
        public ListWebControl(Guid listGuid, bool isSelectJSFunction, bool isMultiselect)
        {
            _listGuid = listGuid;
            _hasListCheckboxes = isSelectJSFunction;
            _isMultiselect = isMultiselect;
        }
        #endregion

        #region Overrides
        /// <summary>
        /// Metoda inicjalizująca webową kontrolkę listy
        /// </summary>
        /// <param name="e">Argumnety</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            try
            {
                InitializeGridView();
                GetListConfiguration();

                _tableWithData = new DataTable();
                _tableWithData.Columns.AddRange(CreateDataColumns());
                FillRows(_tableWithData);
                BindGridView(_tableWithData);

                AddWebControls();
            }
            catch (Exception ex)
            {
                AddErrorMessage(ex.Message);
            }

        }
        #endregion

        #region Methods
        /// <summary>
        /// Pobiera konfigurację listy
        /// </summary>
        private void GetListConfiguration()
        {
            try
            {
                _listConfiguration = (ListConfiguration)Serializer.Deserialize(Policy.List, _listGuid);
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Błąd przy pobieraniu definicji listy {0}: {1}", _listGuid.ToString(), ex.Message));
            }
        }

        /// <summary>
        /// Inicjalizuje GridView
        /// </summary>
        private void InitializeGridView()
        {
            _gridView = new GridView();
            _gridView.Columns.Clear();
            //_gridView.DataKeyNames = new string[] { "m.Id" };

            if (_hasListCheckboxes)
            {
                _gridView.RowDataBound += new GridViewRowEventHandler(ListRowDataBound);
            }

            TemplateField templateMultiSelect = new TemplateField();
            templateMultiSelect.ItemTemplate = new ListMultiselectTemplate();
            _gridView.Columns.Add(templateMultiSelect);

        }

        /// <summary>
        /// Handler dla zdarzenia umieszczania wiersza w GridView
        /// </summary>
        /// <param name="sender">GridView</param>
        /// <param name="e">Argumenty zdarzenia</param>
        private void ListRowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                ((CheckBox)e.Row.FindControl(ListMultiselectTemplate.CheckElementName)).Attributes["onclick"] = "CheckElement('" + ((CheckBox)e.Row.FindControl(ListMultiselectTemplate.CheckElementName)).ClientID + "', '" + GetHowManySeek().ToString() + "'," + ((_isMultiselect) ? QuerryStringConstants.ListMultiselectTrue : QuerryStringConstants.ListMultiselectFalse) + ");";
            }
        }

        /// <summary>
        /// Sprawdza, w której kolumnie znajduje się klucz główny
        /// </summary>
        /// <returns>Numer kolumny, w której znajduje się klucz główny</returns>
        private int GetHowManySeek()
        {
            int index = 0;
            foreach (var element in _listConfiguration.Details.ConfiguredColumns)
            {
                if (element == _listConfiguration.Details.GetPrimaryKeyColumn())
                {
                    return ++index;
                }
                index++;
            }

            throw new Exception("Nie znaleziono klucza głównego na liście");
        }

        /// <summary>
        /// Podpina DataTable jako źródło GridView
        /// </summary>
        /// <param name="table"></param>
        private void BindGridView(DataTable table)
        {
            _gridView.DataSource = table;
            _gridView.DataBind();
        }

        /// <summary>
        /// Tworzy kolumny dla listy
        /// </summary>
        /// <returns>Kolumny dla listy</returns>
        private DataColumn[] CreateDataColumns()
        {
            List<DataColumn> createdColumns = new List<DataColumn>();
            DataColumn newColumn;
            foreach (ConfiguredColumn configuredColumn in _listConfiguration.Details.ConfiguredColumns)
            {
                newColumn = new DataColumn();
                newColumn.ColumnName = configuredColumn.DisplayName;
                newColumn.DataType = typeof(string);
                createdColumns.Add(newColumn);
            }

            return createdColumns.ToArray();
        }

        /// <summary>
        /// Uzupełnia DataTable danymi
        /// </summary>
        /// <param name="table">DataTable do uzupełnienia</param>
        private void FillRows(DataTable table)
        {
            List<Dictionary<string, string>> rows =
                (new HQLQuerryExecutor()).GetRows(
                    _listConfiguration.Details,
                    (ParentId.HasValue) ? _listConfiguration.Details.CreateHqlQuerry().Replace("@ParentId", ParentId.Value.ToString()) : _listConfiguration.Details.CreateHqlQuerry(),
                     null);
            foreach (Dictionary<string, string> createdRow in rows)
            {
                table.Rows.Add(createdRow.Values.ToArray<string>());
            }
        }

        /// <summary>
        /// Dodaje webowe kontrolki do kontrolki listy
        /// </summary>
        private void AddWebControls()
        {
            Table table = new Table();
            TableRow row = null;
            TableCell cell = null;

            if (IsFilter())
            {
                row = new TableRow();
                cell = new TableCell();

                _filterControl = new ListFilterControl(_listConfiguration.Details.FilteredColumns);
                _filterControl.CreateControls();
                _filterControl.SearchClicked += new EventHandler(SearchInvoked);
                cell.Controls.Add(_filterControl);
                row.Cells.Add(cell);
                table.Rows.Add(row);
            }

            row = new TableRow();
            cell = new TableCell();
            cell.Controls.Add(_gridView);
            row.Cells.Add(cell);
            table.Rows.Add(row);
            Controls.Add(table);

            if (_listConfiguration.Actions != null && _listConfiguration.Actions.Count > 0)
            {
                Panel panel = new Panel();

                foreach (ListActionBase action in _listConfiguration.Actions)
                {
                    panel.Controls.Add(action.CreateWebControl());
                    action.ListControl = this;
                }

                Controls.Add(panel);
            }
        }

        /// <summary>
        /// Handler przycisku wyszukaj dla filtru
        /// </summary>
        /// <param name="sender">Przycisk wyszukaj</param>
        /// <param name="e">Argumenty</param>
        private void SearchInvoked(object sender, EventArgs e)
        {
            _tableWithData.Rows.Clear();
            List<Dictionary<string, string>> rows = (new HQLQuerryExecutor()).GetRows(_listConfiguration.Details, _listConfiguration.Details.CreateHqlQuerry(), _filterControl.GetWhereStatement());
            foreach (Dictionary<string, string> createdRow in rows)
            {
                _tableWithData.Rows.Add(createdRow.Values.ToArray<string>());
            }

            BindGridView(_tableWithData);
        }

        /// <summary>
        /// Sprawdza, czy lista posiada filtrowane kolumny
        /// </summary>
        /// <returns>Czy list posiada filgrowane kolumny ?</returns>
        private bool IsFilter()
        {
            return _listConfiguration.Details.FilteredColumns.Count != 0;
        }

        /// <summary>
        /// Pobiera listę zaznaczonych elementów na liście
        /// </summary>
        /// <returns>Lista zaznaczonych elementów na liście</returns>
        public IList<int> GetSelectedIds()
        {
            List<int> list = new List<int>();

            foreach (GridViewRow row in _gridView.Rows)
            {
                if (((CheckBox)row.FindControl(ListMultiselectTemplate.CheckElementName)).Checked)
                {
                    list.Add(int.Parse(row.Cells[GetIdColumnIndex() + 1].Text));
                }
            }

            return list;
        }

        /// <summary>
        /// Pobiera indeks kolumny z kluczem głównym
        /// </summary>
        /// <returns>Indeks kolumny z kluczem głównym</returns>
        private int GetIdColumnIndex()
        {
            for (int counter = 0; counter < _listConfiguration.Details.ConfiguredColumns.Count; counter++)
            {
                if (_listConfiguration.Details.ConfiguredColumns[counter]
                    == _listConfiguration.Details.GetPrimaryKeyColumn())
                {
                    return counter;
                }
            }

            throw new Exception("Nie znaleziono klucza głównego");
        }

        #endregion
    }
}
